//----------------------------------------------------------------------------------------------------------------------
// Copyright (c) 2012 James Whitworth
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//----------------------------------------------------------------------------------------------------------------------
#include "TypeHelpers.h"
//----------------------------------------------------------------------------------------------------------------------

const SQInteger     kExpectedInteger = 1234;
const SQFloat       kExpectedFloat = static_cast<SQFloat>(4321.0);
const SQChar       *kExpectedString = _SC("EXPECTED_STRING");
const bool          kExpectedBool = true;
#if defined(_SQ64)
ptrdiff_t value1 = 0x1234567887654321;
const SQUserPointer kExpectedUserPointer = reinterpret_cast<SQUserPointer>(value1);
ptrdiff_t value2 = 0x8765432112345678;
const SQUserPointer kExpectedInstance = reinterpret_cast<SQUserPointer>(value2);
#else
const SQUserPointer kExpectedUserPointer = reinterpret_cast<SQUserPointer>(0x12345678);
const SQUserPointer kExpectedInstance = reinterpret_cast<SQUserPointer>(0x87654321);
#endif

//----------------------------------------------------------------------------------------------------------------------
// PushObjectOfType
//----------------------------------------------------------------------------------------------------------------------
void PushObjectOfType(HSQUIRRELVM vm, SQObjectType type)
{
  switch (type)
  {
  case OT_NULL:
    sq_pushnull(vm);
    break;
  case OT_INTEGER:
    sq_pushinteger(vm, kExpectedInteger);
    break;
  case OT_FLOAT:
    sq_pushfloat(vm, kExpectedFloat);
    break;
  case OT_BOOL:
    sq_pushbool(vm, (kExpectedBool ? SQTrue : SQFalse));
    break;
  case OT_STRING:
    sq_pushstring(vm, kExpectedString, -1);
    break;
  case OT_TABLE:
    sq_newtable(vm);
    break;
  case OT_ARRAY:
    sq_newarray(vm, 0);
    break;
  case OT_USERDATA:
    sq_newuserdata(vm, 1);
    break;
  case OT_CLOSURE:
    {
      const SQChar *buffer = _SC("return function() { }");
      ASSERT_SQ_SUCCEEDED(vm, sq_compilebuffer(vm, buffer, scstrlen(buffer), _SC("buffer"), SQFalse));
      sq_pushroottable(vm);
      ASSERT_SQ_SUCCEEDED(vm, sq_call(vm, 1, SQTrue, SQFalse));
      sq_remove(vm, -2);
      break;
    }
  case OT_NATIVECLOSURE:
    sq_newclosure(vm, nullptr, 0);
    break;
  case OT_GENERATOR:
    {
      const SQChar *buffer = _SC("function gen(n) { for (local i = 0; i < n; ++i) { yield i } return null } return gen(10)");
      ASSERT_SQ_SUCCEEDED(vm, sq_compilebuffer(vm, buffer, scstrlen(buffer), _SC("buffer"), SQFalse));
      sq_pushroottable(vm);
      ASSERT_SQ_SUCCEEDED(vm, sq_call(vm, 1, SQTrue, SQFalse));
      sq_remove(vm, -2);
      break;
    }
  case OT_USERPOINTER:
    sq_pushuserpointer(vm, kExpectedUserPointer);
    break;
  case OT_THREAD:
    sq_newthread(vm, 128);
    break;
  case OT_CLASS:
    ASSERT_SQ_SUCCEEDED(vm, sq_newclass(vm, SQFalse));
    break;
  case OT_INSTANCE:
    ASSERT_SQ_SUCCEEDED(vm, sq_newclass(vm, SQFalse));
    ASSERT_SQ_SUCCEEDED(vm, sq_createinstance(vm, -1));
    ASSERT_SQ_SUCCEEDED(vm, sq_setinstanceup(vm, -1, kExpectedInstance));
    sq_remove(vm, -2);
    break;
  case OT_WEAKREF:
    sq_pushroottable(vm);
    sq_weakref(vm, -1);
    sq_remove(vm, -2);
    break;
  default:
    break;
  }
}

//----------------------------------------------------------------------------------------------------------------------
// BoundClass
//----------------------------------------------------------------------------------------------------------------------
BoundClass::BoundClass(uint32_t id)
: m_id(id)
{
}

//----------------------------------------------------------------------------------------------------------------------
BoundClass::BoundClass(const BoundClass &rhs)
: m_id(rhs.m_id)
{
}

//----------------------------------------------------------------------------------------------------------------------
const BoundClass &BoundClass::operator = (const BoundClass &rhs)
{
  m_id = rhs.m_id;
  return *this;
}

//----------------------------------------------------------------------------------------------------------------------
bool BoundClass::operator == (const BoundClass &rhs) const
{
  return m_id == rhs.m_id;
}
